package com.example.docmanagement.controller;

import com.example.docmanagement.dto.request.FileMetadataQueryRequest;
import com.example.docmanagement.dto.request.FileUploadRequest;
import com.example.docmanagement.dto.response.ApiResponse;
import com.example.docmanagement.dto.response.FileMetadataResponse;
import com.example.docmanagement.dto.response.PageResponse;
import com.example.docmanagement.entity.FileMetadata;
import com.example.docmanagement.entity.User;
import com.example.docmanagement.repository.UserRepository;
import com.example.docmanagement.service.FileMetadataService;
import com.example.docmanagement.service.MinioService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springdoc.core.annotations.ParameterObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/**
 * 文件管理控制器
 * 提供文件上传、下载、管理等功能
 * 
 * 基础路径：/api/v1/files
 * 
 * 主要功能：
 * - 文件上传（单文件、批量、Markdown）
 * - 文件列表查询
 * - 文件详情查看
 * - 文件下载（Presigned URL）
 * - 文件删除
 */
@RestController
@RequestMapping("/api/v1/files")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "文件管理", description = "文件上传、下载、管理接口")
public class FileController {

    private final FileMetadataService fileMetadataService;
    private final MinioService minioService;
    private final UserRepository userRepository;

    /**
     * 分页查询文件列表
     *
     * 接口路径：GET /api/v1/files
     *
     * @param request 查询条件
     * @return 分页文件数据
     */
    @GetMapping
    @Operation(summary = "文件列表", description = "分页查询 MinIO 文件（默认排除已删除）")
    public ResponseEntity<ApiResponse<PageResponse<FileMetadataResponse>>> getFiles(
            @ParameterObject @ModelAttribute FileMetadataQueryRequest request) {

        PageResponse<FileMetadataResponse> page = fileMetadataService.getFiles(request);
        return ResponseEntity.ok(ApiResponse.success(page));
    }

    /**
     * 上传文件接口
     * 
     * 接口路径：POST /api/v1/files/upload
     * 
     * 功能说明：
     * - 支持图片、文档附件等多种类型
     * - 自动判断文件类型和存储位置
     * - 图片自动压缩和生成缩略图（可选）
     * - 返回文件访问 URL
     * 
     * @param file    上传的文件
     * @param request 上传请求参数（通过查询参数传递）
     * @param userDetails 当前登录用户
     * @return 文件元数据
     */
    @PostMapping("/upload")
    @Operation(summary = "上传文件", description = "上传图片、文档附件等文件到 MinIO")
    public ResponseEntity<ApiResponse<FileMetadataResponse>> uploadFile(
            @RequestParam("file") MultipartFile file,
            @ModelAttribute FileUploadRequest request,
            @AuthenticationPrincipal UserDetails userDetails) {
        
        log.info("收到文件上传请求: {}, 大小: {} bytes", 
                 file.getOriginalFilename(), file.getSize());

        UUID uploadedBy = resolveCurrentUserId(userDetails);

        // 上传文件
        FileMetadata fileMetadata = fileMetadataService.uploadFile(file, request, uploadedBy);
        
        // 转换为 DTO
        FileMetadataResponse response = fileMetadataService.toResponse(fileMetadata);

        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(ApiResponse.success(response, "文件上传成功"));
    }

    /**
     * 上传 Markdown 文本到 MinIO
     * 
     * 接口路径：POST /api/v1/files/upload-markdown
     * 
     * 功能说明：
     * - 将 Markdown 文本内容上传到 MinIO
     * - 返回 MinIO URL，可用作 contentUrl
     * - 适用于大文档（>500KB）
     * 
     * @param requestBody 包含 content 和 fileName 的 Map
     * @param userDetails 当前登录用户
     * @return 文件元数据
     */
    @PostMapping("/upload-markdown")
    @Operation(summary = "上传 Markdown 文本", description = "将 Markdown 文本上传到 MinIO")
    public ResponseEntity<ApiResponse<FileMetadataResponse>> uploadMarkdown(
            @RequestBody Map<String, String> requestBody,
            @AuthenticationPrincipal UserDetails userDetails) {
        
        String content = requestBody.get("content");
        String fileName = requestBody.getOrDefault("fileName", null);

        if (content == null || content.isEmpty()) {
            return ResponseEntity
                    .badRequest()
                    .body(ApiResponse.error("内容不能为空"));
        }

        log.info("收到 Markdown 文本上传请求, 大小: {} bytes", content.length());

        UUID uploadedBy = resolveCurrentUserId(userDetails);

        // 上传 Markdown
        FileMetadata fileMetadata = fileMetadataService.uploadMarkdownText(content, fileName, uploadedBy);
        
        // 转换为 DTO
        FileMetadataResponse response = fileMetadataService.toResponse(fileMetadata);

        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(ApiResponse.success(response, "Markdown 文件上传成功"));
    }

    /**
     * 批量上传文件接口
     * 
     * 接口路径：POST /api/v1/files/batch-upload
     * 
     * 功能说明：
     * - 一次上传多个文件（最多 10 个）
     * - 返回每个文件的上传结果
     * - 部分失败不影响其他文件
     * 
     * @param files 文件数组
     * @param request 上传请求参数
     * @param userDetails 当前登录用户
     * @return 批量上传结果
     */
    @PostMapping("/batch-upload")
    @Operation(summary = "批量上传文件", description = "一次上传多个文件")
    public ResponseEntity<ApiResponse<Map<String, Object>>> batchUpload(
            @RequestParam("files") MultipartFile[] files,
            @ModelAttribute FileUploadRequest request,
            @AuthenticationPrincipal UserDetails userDetails) {
        
        log.info("收到批量上传请求，文件数量: {}", files.length);

        // 检查文件数量
        Integer maxBatchSize = 10;  // TODO: 从配置读取
        if (files.length > maxBatchSize) {
            return ResponseEntity
                    .badRequest()
                    .body(ApiResponse.error("一次最多上传 " + maxBatchSize + " 个文件"));
        }

        UUID uploadedBy = resolveCurrentUserId(userDetails);

        // 上传结果列表
        List<Map<String, Object>> results = new ArrayList<>();
        int successCount = 0;
        int failedCount = 0;

        for (MultipartFile file : files) {
            Map<String, Object> result = new HashMap<>();
            result.put("fileName", file.getOriginalFilename());

            try {
                FileMetadata fileMetadata = fileMetadataService.uploadFile(file, request, uploadedBy);
                FileMetadataResponse response = fileMetadataService.toResponse(fileMetadata);
                
                result.put("status", "success");
                result.put("fileId", response.getId());
                result.put("fileUrl", response.getFileUrl());
                successCount++;
            } catch (Exception e) {
                result.put("status", "failed");
                result.put("error", e.getMessage());
                failedCount++;
                log.error("文件上传失败: " + file.getOriginalFilename(), e);
            }

            results.add(result);
        }

        // 构建响应
        Map<String, Object> data = new HashMap<>();
        data.put("successCount", successCount);
        data.put("failedCount", failedCount);
        data.put("results", results);

        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(ApiResponse.success(data, "批量上传完成"));
    }

    /**
     * 获取文件详情接口
     * 
     * 接口路径：GET /api/v1/files/{id}
     * 
     * @param id 文件 ID
     * @return 文件详情
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取文件详情", description = "根据 ID 获取文件详细信息")
    public ResponseEntity<ApiResponse<FileMetadataResponse>> getFileById(@PathVariable Long id) {
        FileMetadata fileMetadata = fileMetadataService.findById(id);
        FileMetadataResponse response = fileMetadataService.toResponse(fileMetadata);
        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * 获取文件下载链接接口
     * 
     * 接口路径：GET /api/v1/files/{id}/download
     * 
     * 功能说明：
     * - 公开文件：返回直接访问 URL
     * - 私有文件：返回 Presigned URL（临时链接）
     * - 需要权限验证
     * 
     * @param id            文件 ID
     * @param expirySeconds URL 有效期（秒），默认 3600
     * @param userDetails   当前登录用户
     * @return 下载链接信息
     */
    @GetMapping("/{id}/download")
    @Operation(summary = "获取文件下载链接", description = "获取文件下载 URL，私有文件返回临时链接")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getDownloadUrl(
            @Parameter(description = "文件ID", required = true, example = "1") @PathVariable Long id,
            @Parameter(description = "下载链接有效期（秒）", example = "3600") @RequestParam(defaultValue = "3600") Integer expirySeconds,
            @AuthenticationPrincipal UserDetails userDetails) {
        
        try {
            FileMetadata file = fileMetadataService.findById(id);

            // TODO: 实现权限检查逻辑
            // 如果是私有文件，检查用户是否有权限下载

            Map<String, Object> data = new HashMap<>();
            data.put("fileId", file.getId());
            data.put("fileName", file.getFileName());
            data.put("accessPolicy", file.getAccessPolicy());

            // 根据访问策略生成不同的 URL
            if ("public".equals(file.getAccessPolicy())) {
                // 公开文件：直接 URL
                String downloadUrl = minioService.getPublicUrl(file.getFilePath());
                data.put("downloadUrl", downloadUrl);
                data.put("expiresAt", null);
            } else {
                // 私有文件：Presigned URL
                String presignedUrl = minioService.getPresignedUrl(file.getFilePath(), expirySeconds);
                data.put("downloadUrl", presignedUrl);
                data.put("expiresAt", java.time.LocalDateTime.now().plusSeconds(expirySeconds));
            }

            return ResponseEntity.ok(ApiResponse.success(data));

        } catch (Exception e) {
            log.error("获取下载链接失败: " + id, e);
            return ResponseEntity
                    .status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(ApiResponse.error("获取下载链接失败: " + e.getMessage()));
        }
    }

    /**
     * 删除文件接口
     * 
     * 接口路径：DELETE /api/v1/files/{id}
     * 
     * 功能说明：
     * - 默认软删除（仅标记，不删除 MinIO 文件）
     * - permanent=true 时物理删除（同时删除 MinIO 文件）
     * - 需要权限：文件所有者或管理员
     * 
     * @param id         文件 ID
     * @param permanent  是否物理删除
     * @param userDetails 当前登录用户
     * @return 删除结果
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除文件", description = "删除文件（软删除或物理删除）")
    public ResponseEntity<ApiResponse<Map<String, Object>>> deleteFile(
            @Parameter(description = "文件ID", required = true, example = "1") @PathVariable Long id,
            @Parameter(description = "是否物理删除，true 表示删除 MinIO 上的文件", example = "false")
            @RequestParam(defaultValue = "false") Boolean permanent,
            @AuthenticationPrincipal UserDetails userDetails) {
        
        UUID currentUserId = resolveCurrentUserId(userDetails);

        try {
            if (Boolean.TRUE.equals(permanent)) {
                // 物理删除
                fileMetadataService.permanentDelete(id);
            } else {
                // 软删除
                fileMetadataService.softDelete(id, currentUserId);
            }

            Map<String, Object> data = new HashMap<>();
            data.put("id", id);
            data.put("deleted", true);
            data.put("permanent", permanent);
            data.put("deletedAt", java.time.LocalDateTime.now());

            return ResponseEntity.ok(ApiResponse.success(data, "文件删除成功"));

        } catch (Exception e) {
            log.error("文件删除失败: " + id, e);
            return ResponseEntity
                    .status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(ApiResponse.error("文件删除失败: " + e.getMessage()));
        }
    }

    /**
     * 获取文档关联的所有文件
     * 
     * 接口路径：GET /api/v1/files/document/{documentId}
     * 
     * @param documentId 文档 ID
     * @param fileType   文件类型筛选（可选）
     * @return 文件列表
     */
    @GetMapping("/document/{documentId}")
    @Operation(summary = "获取文档文件", description = "获取文档关联的所有文件")
    public ResponseEntity<ApiResponse<List<FileMetadataResponse>>> getDocumentFiles(
            @Parameter(description = "文档ID", required = true, example = "10") @PathVariable Long documentId,
            @Parameter(description = "文件类型筛选，如 image、document", example = "image")
            @RequestParam(required = false) String fileType) {
        
        List<FileMetadata> files;
        if (fileType != null && !fileType.isEmpty()) {
            files = fileMetadataService.findByDocumentIdAndType(documentId, fileType);
        } else {
            files = fileMetadataService.findByDocumentId(documentId);
        }

        List<FileMetadataResponse> responses = files.stream()
                .map(fileMetadataService::toResponse)
                .collect(java.util.stream.Collectors.toList());

        return ResponseEntity.ok(ApiResponse.success(responses));
    }

    private UUID resolveCurrentUserId(UserDetails userDetails) {
        if (userDetails == null) {
            throw new AccessDeniedException("未登录或登录状态已失效");
        }
        String username = userDetails.getUsername();
        Optional<User> currentUser = userRepository.findByEmailOrUsername(username, username);
        return currentUser
                .filter(user -> user.getDeletedAt() == null)
                .map(User::getId)
                .orElseThrow(() -> new AccessDeniedException("当前用户不存在或已被禁用"));
    }
}

